#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：turbo 
@File    ：serializers.py
@Author  ：赵加响
@Date    ：2023/4/3 16:57 
@Desc    ：自定义Serializer，继承六大字段填入混入、序列化数据校验混入、ModelSerializer、
           减少实际开发的代码量
"""
from copy import deepcopy

from django.db import transaction
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.fields import empty
from rest_framework.request import Request
from rest_framework.serializers import ModelSerializer

from apps.codetable.models import CodeTableDetail
from bases.mixins import SixFieldsUpdateMixIn, SerializerValidateMixIn
from bases.types import ValidateDescDict
from constants import LANGUAGE_ZH


class APIModelSerializer(SixFieldsUpdateMixIn, SerializerValidateMixIn, ModelSerializer):
    """
    DRF在进行序列化时加入常用的数据校验方式
    """
    require_fields: tuple = ()  # 数据新建、更新时必输项字段
    unique_fields: tuple = ()  # 数据新建、更新时唯一性校验字段，元素只能为字符串和元组（元组中的元组的元素只能为字符串）
    non_updatable_fields: tuple = ()  # 不可更新字段，一般用于在特定的状态下部分数据不可修改
    validate_desc: ValidateDescDict = {'table': None, 'field': None, 'status': None,
                                       'value': None}  # 验证描述字典，在{status}下，{table}表中的{field}字段值为{value}时不可更新

    # 通用Model中应该包含该六大字段，因此在继承APIModelSerializer中默认将其输出
    created = serializers.ReadOnlyField(source='created.name')
    created_date = serializers.DateTimeField(read_only=True)
    created_program = serializers.ReadOnlyField()
    updated = serializers.ReadOnlyField(source='updated.name')
    updated_date = serializers.DateTimeField(read_only=True)
    updated_program = serializers.ReadOnlyField()

    def __init__(self, instance=None, data=empty, request=None, **kwargs):
        super().__init__(instance, data, **kwargs)
        self.request: Request = request or self.context.get('request', None)
        self.model = self.Meta.model
        self.localization = getattr(self.request, 'LANGUAGE_CODE', LANGUAGE_ZH)

    class Meta:
        """
        Meta中指定该六大字段，子类Serializer中可以在Meta类（元类）中使用fields='__all__'显示全部的字段
         class Meta:
            model = Samples
            fields = '__all__'

        如果显示自定义字段+六大字段可以使用以下两种方法
        1.继承的方式
        class Meta(APIModelSerializer.Meta):
            model = Samples
            fields = ('item_no',) + APIModelSerializer.Meta.fields

        2.直接写需要显示的字段
        class Meta:
            model = Samples
            fields = ('item_no', 'status', 'created', 'created_date', 'created_program')
        """
        fields = ('created', 'created_date', 'created_program', 'updated', 'updated_date', 'updated_program')

    def validate(self, attrs):
        """
        validate中增加新建接口必输项校验，更新接口不可修改字段校验
        """
        serializer_fields = self.fields
        validate_attrs = attrs

        if self.request.method.lower() == 'post':
            # 数据新建时进行必输项校验
            self.handle_require_fields(serializer_fields, validate_attrs, self.require_fields)
            # 数据新建时进行数据唯一性校验
            self.handle_unique_fields(self.model, serializer_fields, validate_attrs, self.unique_fields)

        if self.request.method.lower() == 'put':
            # 数据更新时进行不可更新字段校验
            if len(self.non_updatable_fields) > 0:
                try:
                    if self.validate_desc['table'] and self.validate_desc['field'] and \
                            self.validate_desc['status'] and self.validate_desc['value']:
                        self.handle_non_updatable(serializer_fields, self.instance, validate_attrs,
                                                  self.non_updatable_fields, self.validate_desc)
                except KeyError:
                    raise ValueError(
                        "System Error: The validate description parameter must be assigned "
                        "when there are non-updatable fields.(bases/serializers.py -> validate_desc)")

            # 数据更新时进行数据唯一性校验
            self.handle_unique_fields(self.model, serializer_fields, validate_attrs, self.unique_fields,
                                      self.instance, update=True)

        if self.has_validation():
            error_msg_dict = deepcopy(self.show_validation())
            self.clear_validation()
            raise ValidationError(error_msg_dict)
        return attrs

    def validate_max_length(self):
        pass

    def field_desc(self, field, value, model=None):
        """
        Args:
            field: 字段名
            value: 字段对应的值
            model: 模型，默认为空，为空时默认为当前model名

        Returns: 该语言下某个模型中字段值对应的说明
        """
        if not model:
            model = self.model.__name__
        try:
            code_detail = CodeTableDetail.objects.get(codetable_head__field__exact=field,
                                                      codetable_head__model__exact=model,
                                                      localization=self.localization,
                                                      code__exact=value)
        except CodeTableDetail.DoesNotExist:
            return ''
        return code_detail.name

    @transaction.atomic
    def create(self, validated_data):
        if hasattr(self.model, 'created_program'):
            self.create_set(self.request, validated_data)

        return super().create(validated_data)

    @transaction.atomic
    def update(self, instance, validated_data):
        if hasattr(self.model, 'updated_program'):
            self.update_set(self.request, validated_data)

        return super().update(instance, validated_data)
